/*
	This file is part of AVRCppLib.

    AVRCppLib is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    AVRCppLib is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with AVRCppLib.  If not, see <http://www.gnu.org/licenses/>.

    Copyright (C) Maxime Lemonnier 2007-2011
 */

#ifndef Counter_H_
#define Counter_H_
#include "../Utils/CppExtensions.h"
#include "../Utils/BitManipulation.h"
#include "../CallbackServers/CallbackConnector.h"
#include "Prescalers.h"
#include "TimerOutputCompareModes.h"
#include "TimerWaveGenerationModes.h"

namespace Timers
{

using Prescalers::Prescaler;

using WaveGenerationModes::WaveGenerationMode4bits;

template <typename IOAddressType, typename uint_t>
class Counter : public CallbackConnector
{
public :

	Counter(uint8_t callbackVectorNumber, IOAddressType tcnt, IOAddress tccrb, uint8_t csMask, IOAddress timsk, uint8_t toie, IOAddress tifr, uint8_t tov);
	inline void setPrescaler(Prescaler prescaler) const FORCE_INLINE;
	inline uint_t read() const FORCE_INLINE;
	inline void setValue(uint_t value) const FORCE_INLINE;

	inline void enableOVFInterrupts() const FORCE_INLINE;
	inline void disableOVFInterrupts() const FORCE_INLINE;
	inline bool readOVFFlag() const FORCE_INLINE;
	inline void clearOVFFlag() const FORCE_INLINE;

protected :

	IOAddressType tcnt;
	IOAddress tccrb;
	uint8_t csMask;
	IOAddress timsk;
	uint8_t toie;
	IOAddress tifr;
	uint8_t tov;
};

typedef Counter<IOAddress, uint8_t> Counter8;
typedef Counter<IOAddress16, uint16_t> Counter16;

template <typename IOAddressType, typename uint_t>
void Counter<IOAddressType, uint_t>::setPrescaler(Prescaler prescaler) const
{
	setConfig(tccrb, csMask, prescaler);
}

template <typename IOAddressType, typename uint_t>
uint_t Counter<IOAddressType, uint_t>::read() const
{
	return *tcnt;
}

template <typename IOAddressType, typename uint_t>
void Counter<IOAddressType, uint_t>::setValue(uint_t value) const
{
	*tcnt = value;
}

template <typename IOAddressType, typename uint_t>
void Counter<IOAddressType, uint_t>::enableOVFInterrupts() const
{
	setBit(*timsk, toie);
}

template <typename IOAddressType, typename uint_t>
void Counter<IOAddressType, uint_t>::disableOVFInterrupts() const
{
	clearBit(*timsk, toie);
}

template <typename IOAddressType, typename uint_t>
bool Counter<IOAddressType, uint_t>::readOVFFlag() const
{
	return bitIsSetInRegister(*tifr, tov);
}

template <typename IOAddressType, typename uint_t>
void Counter<IOAddressType, uint_t>::clearOVFFlag() const
{
	setBit(*tifr, tov);
}

}

#endif /* Counter_H_ */
